<?php
/**
 * vanephp web framework
 * 常用功能函数
 *
 * @author aray <ofree@qq.com>
 * @link http://www.vanephp.com/
 * @copyright Copyright &copy; 2010 aray
 * @license http://www.vanephp.com/license
 * @package util
 */

if ( ! defined ( 'INVANE' ) )
	exit ( '!' );

function url ( $controller = null, $action = null, $args = array() ) {
	$url = getAppPath ( ) . '/';
	
	static $controller_accessor = null , $action_accessor = null , $index_filename = null , $hide_indexfilename = null , $current_filename = null , $url_mode = null;
	if ( $controller_accessor === null )
		$controller_accessor = config::get ( 'controller_accessor' );
	if ( $action_accessor === null )
		$action_accessor = config::get ( 'action_accessor' );
	if ( $index_filename === null )
		$index_filename = config::get ( 'index_filename' );
	if ( $hide_indexfilename === null )
		$hide_indexfilename = config::get ( 'hide_index_filename' );
	if ( $current_filename === null )
		$current_filename = basename ( $_SERVER['SCRIPT_NAME'] );
	if ( $url_mode === null )
		$url_mode = config::get ( 'url_mode' );
	
	$queryString = '';
	
	if ( $url_mode != 'url_rewrite' ) {
		if ( $hide_indexfilename == 'true' ) {
			if ( $current_filename == $index_filename ) {
				$queryString = '?';
			} else {
				$queryString = $current_filename;
			}
		} else {
			$queryString = $current_filename;
		}
	}
	
	# 去除args中的覆盖设置
	if ( is_array ( $args ) ) {
		if ( isset ( $args[config::get ( 'controller_accessor' )] ) ) {
			unset ( $args[config::get ( 'controller_accessor' )] );
		}
		if ( isset ( $args[config::get ( 'action_accessor' )] ) ) {
			unset ( $args[config::get ( 'action_accessor' )] );
		}
	}
	# 根据URL模式生成URL
	$controller = ($controller == null || $controller == '') ? config::get ( 'default_controller' ) : $controller;
	$params = array (
		$controller_accessor => $controller, $action_accessor => $action 
	);
	
	switch ( config::get ( 'url_mode' ) ) {
		case 'url_get' :
			if ( is_array ( $args ) ) {
				$queryString .= http_build_query ( array_merge ( $params, $args ) );
			} else {
				$queryString .= http_build_query ( $params ) . (substr ( $args, 0, 1 ) == '&' ? '' : '&') . $args;
			}
			break;
		default :
			static $pathinfo_separtor = null;
			if ( $pathinfo_separtor == null )
				$pathinfo_separtor = config::get ( 'pathinfo_separator' );
			
			if ( is_array ( $args ) ) {
				$queryString .= '/' . http_build_query ( array_merge ( $params, $args ) );
			} else {
				$queryString .= '/' . http_build_query ( $params ) . (substr ( $args, 0, 1 ) == '&' ? '' : '&') . $args;
			}
			$queryString = str_replace ( '&', $pathinfo_separtor, $queryString );
			$queryString = str_replace ( '=', $pathinfo_separtor, $queryString );
			$queryString = str_replace ( $controller_accessor . $pathinfo_separtor, '', $queryString );
			$queryString = str_replace ( $action_accessor . $pathinfo_separtor, '', $queryString );
			break;
	}
	
	$url .= $queryString;
	
	return $url;
}

/**
 * 获取http协议的主机名称
 * @return string
 */
function getAppHostname ( ) {
	return (isset ( $_SERVER['HTTPS'] ) ? 'https://' : 'http://') . $_SERVER['SERVER_NAME'];
}

/**
 * 获取当前应用路径
 * @return string
 */
function getAppPath ( ) {
	return str_replace ( $_SERVER['DOCUMENT_ROOT'], '', dirname ( $_SERVER['SCRIPT_FILENAME'] ) );
}

/**
 * 获取当前应用文件路径
 * @return string
 */
function getAppFilename ( ) {
	return str_replace ( $_SERVER['DOCUMENT_ROOT'], '', $_SERVER['SCRIPT_FILENAME'] );
}

/**
 *
 * @param $url string 跳转地址
 * @param $client boolean 是否为客户端跳转
 */
function redirect ( $url, $delay = -1 ) {
	$referer = getAppHostname ( ) . $_SERVER['REQUEST_URI'];
	header ( "Referer: $referer\n\n" );
	
	if ( $delay == - 1 ) {
		header ( "Location: $url\n\n" );
	} else {
		$html = <<<DOCHERE
<html>
<head>
<meta http-equiv="refresh" content="$delay; url=$url" />
<script language="javascript">
function redirect(){
	setTimeout(function(){
		document.location.href = "$url";
	}, $delay * 1000);
}
window.onload = redirect;
</script>
</head>
<body onload="redirect()">
</body>
</html>
DOCHERE;
		exit ( $html );
	}
}

/**
 * 将GB2312转换为UTF-8
 * @param $utf8Str
 * @return string
 */
function toUtf8 ( $utf8Str ) {
	return iconv ( 'GB2312', 'UTF-8//IGNORE', $utf8Str );
}

/**
 * 将UTF-8转换为GB2312
 * @param $gbStr
 * @return string
 */
function toGb2312 ( $gbStr ) {
	return iconv ( 'UTF-8', 'GB2312//IGNORE', $gbStr );
}

/**
 * BOM检查
 * @param string $filename
 * @return boolean
 */
function isBOM ( $filename ) {
	$contents = file_get_contents ( $filename );
	$charset[1] = substr ( $contents, 0, 1 ); // EF
	$charset[2] = substr ( $contents, 1, 1 ); // BB
	$charset[3] = substr ( $contents, 2, 1 ); // BF
	if ( ord ( $charset[1] ) == 239 && ord ( $charset[2] ) == 187 && ord ( $charset[3] ) == 191 ) {
		return true;
	}
	return false;
}

/**
 * 检查文件编码
 * @param string $str
 * @return boolean
 */
function isUTF8File ( $filename ) {
	$str = file_get_contents ( $filename );
	if ( $str === mb_convert_encoding ( mb_convert_encoding ( $str, 'UTF-32', 'UTF-8' ), 'UTF-8', 'UTF-32' ) ) {
		return true;
	}
	return false;
}

/**
 * 是否为UTF8字符
 * @param string $str
 * @return boolean
 */
function isUTF8Str ( $str ) {
	if ( $str === mb_convert_encoding ( mb_convert_encoding ( $str, 'UTF-32', 'UTF-8' ), 'UTF-8', 'UTF-32' ) ) {
		return true;
	}
	return false;
}

/**
 * 判断是否为POST方式请求
 * @return boolean
 */
function isPOST ( ) {
	$flag = false;
	if ( isset ( $_SERVER['REQUEST_METHOD'] ) && $_SERVER['REQUEST_METHOD'] == 'POST' ) {
		$flag = true;
	}
	return $flag;
}

/**
 * 判断是否为AJAX方式请求
 * @return boolean
 */
function isAJAX ( ) {
	$flag = false;
	if ( isset ( $_SERVER['HTTP_X_REQUESTED_WITH'] ) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest' ) {
		$flag = true;
	}
	return $flag;
}

/**
 * 获取随机字符串
 * @param $len			随机数长度
 * @param $randType		随机数类型
 * @return string
 */
function getRandStr ( $len = 6, $randType = 1 ) {
	$str = '';
	switch ( $randType ) {
		case 1 :
			$str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
			break;
		case 2 :
			$str = '0123456789';
			break;
		default :
			$str = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxy23456789';
	}
	
	$strlen = strlen ( $str );
	$randStr = '';
	while ( strlen ( $randStr ) < $len ) {
		$randStr .= $str[mt_rand ( 0, $strlen - 1 )];
	}
	return $randStr;
}

/**
 * 向浏览器发送文件内容
 *
 * @param string $serverPath 文件在服务器上的路径（绝对或者相对路径）
 * @param string $filename 发送给浏览器的文件名（尽可能不要使用中文）
 * @param string $mimeType 指示文件类型
 */
function sendFile ( $serverPath, $filename, $mimeType = 'application/octet-stream' ) {
	header ( "Content-Type: {$mimeType}\n\n" );
	
	$filename = '"' . htmlspecialchars ( $filename ) . '"';
	$filesize = filesize ( $serverPath );
	$filename = toGB2312 ( $filename );
	$charset = config::get ( 'response_charset' );
	header ( "Content-Disposition: attachment; filename={$filename}; charset={$charset}\n\n" );
	header ( "Pragma: cache\n\n" );
	header ( "Cache-Control: public, must-revalidate, max-age=0\n\n" );
	header ( "Content-Length: {$filesize}\n\n" );
	readfile ( $serverPath );
	exit ( );
}

/**
 * 返回客户端IP地址
 * @return 
 */
function getIp ( ) {
	return $_SERVER['REMOTE_ADDR'];
}

/**
 * 支持中文的substr
 * @param string $str
 * @param int $from
 * @param int $len
 * @param string $fix
 * @return string
 */
function _substr ( $str, $from, $len, $fix = '' ) {
	preg_match_all ( '#(?:[\x00-\x7F]|[\xC0-\xFF][\x80-\xBF]+)#s', $str, $array, PREG_PATTERN_ORDER );
	$from1 = 0;
	$len1 = 0;
	$s = '';
	foreach ( $array[0] as $key => $val ) {
		$n = ord ( $val ) >= 128 ? 2 : 1;
		$from1 += $n;
		if ( $from1 > $from ) {
			$len1 += $n;
			if ( $len1 <= $len ) {
				$s .= $val;
			} else {
				return $s . $fix;
			}
		}
	}
	return $s;
}

/**
 * 载入YAML文件
 * @param $file
 * @return array
 */
function loadYaml ( $file ) {
	require_once (VANEDIR . DS . '3rd' . DS . 'spyc.php');
	$parser = new Spyc ( );
	return $parser->load ( $file );
}

/**
 * 将树形结构的数组转换成select表单
 * @param array $categories
 * @param int $level
 * @param int $selected
 * @param string $key
 * @param string $val
 */
function getOptionList ( $categories, $level = 0, $selected = 0, $childrens = 'childrens', $key = 'categoryid', $val = 'category' ) {
	$options = '';
	foreach ( $categories as $category ) {
		if ( isset ( $category['childrens'] ) && is_array ( $category[$childrens] ) ) {
			$options .= sprintf ( '<option hasChildren="true" value="%d" %s>%s %s</option>' . "\r\n", $category['categoryid'], ($selected == $category[$key]) ? 'selected initSelect="true" style="color:#f00;"' : '', str_repeat ( '&nbsp;&nbsp;&nbsp;', $level ) . '└', $category[$val] );
			$level ++;
			$options .= getOptionList ( $category[$childrens], $level, $selected, $childrens, $key, $val );
			$level --;
		} else {
			$options .= sprintf ( '<option value="%d" %s>%s %s</option>' . "\r\n", $category[$key], ($selected == $category[$key]) ? 'selected initSelect="true" style="color:#f00;"' : '', str_repeat ( '&nbsp;&nbsp;&nbsp;', $level ) . '├', $category[$val] );
		}
	}
	return $options;
}

/**
 * 替换<>html标记
 * @param $str
 */
function t ( $str ) {
	$str = str_replace ( '<', '&lt;', $str );
	$str = str_replace ( '>', '&gt;', $str );
	return $str;
}

/**
 * 随机获取中文字符
 * @param int $len
 * @return string
 */
function getRandChinese ( $len = 4 ) {
	$chs = '的一是在了不和有大这主中人上为们地个用工时要动国产以我到他会作来分生对于学下级就年阶义发成部民可出能方进同行面说种过命度革而多子后自社加小机也经力线本电高量长党得实家定深法表着水理化争现所二起政三好十战无农使性前等反体合斗路图把结第里正新开论之物从当两些还天资事队批如应形想制心样干都向变关点育重其思与间内去因件日利相由压员气业代全组数果期导平各基或月毛然问比展那它最及外没看治提五解系林者米群头意只明四道马认次文通但条较克又公孔领军流入接席位情运器并飞原油放立题质指建区验活众很教决特此常石强极土少已根共直团统式转别造切九你取西持总料连任志观调七么山程百报更见必真保热委手改管处己将修支识病象几先老光专什六型具示复安带每东增则完风回南广劳轮科北打积车计给节做务被整联步类集号列温装即毫知轴研单色坚据速防史拉世设达尔场织历花受求传口断况采精金界品判参层止边清至万确究书术状厂须离再目海交权且儿青才证低越际八试规斯近注办布门铁需走议县兵固除般引齿千胜细影济白格效置推空配刀叶率述今选养德话查差半敌始片施响收华觉备名红续均药标记难存测士身紧液派准斤角降维板许破述技消底床田势端感往神便贺村构照容非搞亚磨族火段算适讲按值美态黄易彪服早班麦削信排台声该击素张密害侯草何树肥继右属市严径螺检左页抗苏显苦英快称坏移约巴材省黑武培著河帝仅针怎植京助升王眼她抓含苗副杂普谈围食射源例致酸旧却充足短划剂宣环落首尺波承粉践府鱼随考刻靠够满夫失包住促枝局菌杆周护岩师举曲春元超负砂封换太模贫减阳扬江析亩木言球朝医校古呢稻宋听唯输滑站另卫字鼓刚写刘微略范供阿块某功套友限项余倒卷创律雨让骨远帮初皮播优占死毒圈伟季训控激找叫云互跟裂粮粒母练塞钢顶策双留误础吸阻故寸盾晚丝女散焊功株亲院冷彻弹错散商视艺灭版烈零室轻血倍缺厘泵察绝富城冲喷壤简否柱李望盘磁雄似困巩益洲脱投送奴侧润盖挥距触星松送获兴独官混纪依未突架宽冬章湿偏纹吃执阀矿寨责熟稳夺硬价努翻奇甲预职评读背协损棉侵灰虽矛厚罗泥辟告卵箱掌氧恩爱停曾溶营终纲孟钱待尽俄缩沙退陈讨奋械载胞幼哪剥迫旋征槽倒握担仍呀鲜吧卡粗介钻逐弱脚怕盐末阴丰编印蜂急拿扩伤飞露核缘游振操央伍域甚迅辉异序免纸夜乡久隶缸夹念兰映沟乙吗儒杀汽磷艰晶插埃燃欢铁补咱芽永瓦倾阵碳演威附牙芽永瓦斜灌欧献顺猪洋腐请透司危括脉宜笑若尾束壮暴企菜穗楚汉愈绿拖牛份染既秋遍锻玉夏疗尖殖井费州访吹荣铜沿替滚客召旱悟刺脑措贯藏敢令隙炉壳硫煤迎铸粘探临薄旬善福纵择礼愿伏残雷延烟句纯渐耕跑泽慢栽鲁赤繁境潮横掉锥希池败船假亮谓托伙哲怀割摆贡呈劲财仪沉炼麻罪祖息车穿货销齐鼠抽画饲龙库守筑房歌寒喜哥洗蚀废纳腹乎录镜妇恶脂庄擦险赞钟摇典柄辩竹谷卖乱虚桥奥伯赶垂途额壁网截野遗静谋弄挂课镇妄盛耐援扎虑键归符庆聚绕摩忙舞遇索顾胶羊湖钉仁音迹碎伸灯避泛亡答勇频皇柳哈揭甘诺概宪浓岛袭谁洪谢炮浇斑讯懂灵蛋闭孩释乳巨徒私银伊景坦累匀霉杜乐勒隔弯绩招绍胡呼痛峰零柴簧午跳居尚丁秦稍追梁折耗碱殊岗挖氏刃剧堆赫荷胸衡勤膜篇登驻案刊秧缓凸役剪川雪链渔啦脸户洛孢勃盟买杨宗焦赛旗滤硅炭股坐蒸凝竟陷枪黎救冒暗洞犯筒您宋弧爆谬涂味津臂障褐陆啊健尊豆拔莫抵桑坡缝警挑污冰柬嘴啥饭塑寄赵喊垫康遵牧遭幅园腔订香肉弟屋敏恢忘衣孙龄岭骗休借丹渡耳刨虎笔稀昆浪萨茶滴浅拥穴覆伦娘吨浸袖珠雌妈紫戏塔锤震岁貌洁剖牢锋疑霸闪埔猛诉刷狠忽灾闹乔唐漏闻沈熔氯荒茎男凡抢像浆旁玻亦忠唱蒙予纷捕锁尤乘乌智淡允叛畜俘摸锈扫毕璃宝芯爷鉴秘净蒋钙肩腾枯抛轨堂拌爸循诱祝励肯酒绳穷塘燥泡袋朗喂铝软渠颗惯贸粪综墙趋彼届墨碍启逆卸航雾冠丙街莱贝辐肠付吉渗瑞惊顿挤秒悬姆烂森糖圣凹陶词迟蚕亿矩';
	$l = strlen ( $chs ) / 1;
	$return = '';
	while ( strlen ( $return ) < $len * 3 ) {
		$r = mt_rand ( 0, $l - 1 ) * 3;
		$return .= substr ( $chs, $r, 3 );
	}
	return $return;
}

/**
 * 获取随机姓氏
 */
function getRandChineseFirstname ( ) {
	$chs = '李王张刘陈杨赵黄周吴徐孙朱马胡郭林何高梁郑罗宋谢唐韩曹许邓萧冯曾程蔡彭潘袁于董余苏叶吕魏蒋田杜丁沈姜范江傅钟卢汪戴崔任陆廖姚方金邱夏谭韦贾邹石熊孟秦阎薛侯雷白龙段郝孔邵史毛常万顾赖武康贺严尹钱施牛洪龚';
	$l = strlen ( $chs ) / 3;
	$return = '';
	$r = mt_rand ( 0, $l - 1 ) * 3;
	$return .= substr ( $chs, $r, 3 );
	return $return;
}

/**
 * 是否为中文
 * @param string $str
 */
function isChinese ( $str ) {
	return preg_match ( '/([\x80-\xFE][\x40-\x7E\x80-\xFE])+/', $str );
}

function getErrorSource ( $filename, $line ) {
	if ( ! file_exists ( $filename ) ) {
		return;
	}
	$data = file ( $filename );
	$count = count ( $data ) - 1;
	$start = $line - 10;
	if ( $start < 1 ) {
		$start = 1;
	}
	$end = $line + 10;
	if ( $end > $count ) {
		$end = $count + 1;
	}
	$returns = array ();
	for ( $i = $start ; $i <= $end ; $i ++ ) {
		if ( $i == $line ) {
			$returns[] = '<div class="codeline breakline"><span class="breaknbsp">→' . $i . '</span>' . highlightSource ( $data[$i - 1], TRUE ) . '</div>';
		} else {
			$returns[] = '<div class="codeline"><span class="nbsp">&nbsp;' . $i . '</span>' . highlightSource ( $data[$i - 1], TRUE ) . '</div>';
		}
	}
	return $returns;
}
function highlightSource ( $code ) {
	if ( ereg ( '<\?(php)?[^[:graph:]]', $code ) ) {
		$code = highlight_string ( $code, TRUE );
	} else {
		$code = ereg_replace ( '(&lt;\?php&nbsp;)+', '', highlight_string ( '<?php ' . $code, TRUE ) );
	}
	return $code;
}

/**
 * 计算参数时间与当前时间差，精确的秒，最大单位天
 * @param int $times
 * @return string
 */
function puttime ( $times ) {
	if ( $times == '' || $times == 0 )
		return false;
	$dtime = is_int ( $times ) ? $times : strtotime ( $times );
	$ptime = time ( ) - $dtime;
	if ( $ptime < 60 ) {
		$pct = sprintf ( "%d秒前", $ptime );
	} else if ( $ptime > 60 && $ptime < 3600 ) {
		$pct = sprintf ( "%d分钟前", ceil ( $ptime / 60 ) );
	} else if ( $ptime > 3600 && $ptime < (3600 * 24) ) {
		$pct = sprintf ( "%d小时%d分钟前", floor ( $ptime / 3600 ), ceil ( ($ptime % 3600) / 60 ) );
	} else if ( $ptime > (3600 * 24) && $ptime < (3600 * 24 * 30) ) {
		$d = $ptime / (3600 * 24);
		$h = ($ptime % (3600 * 24)) / 3600;
		$m = ceil ( (($ptime % (3600 * 24)) % 3600) / 60 );
		$pct = sprintf ( "%d天%d小时%d分钟前", $d, $h, $m );
	} else {
		$mt = $ptime / (3600 * 24 * 30);
		$d = ($ptime % (3600 * 24 * 30)) / (3600 * 24);
		$h = (($ptime % (3600 * 24 * 30)) % (3600 * 24)) / 3600;
		$m = ceil ( (($ptime % (3600 * 24 * 30)) % (3600 * 24)) % 3600 / 60 );
		$pct = sprintf ( "%d月%d天%d小时%d分钟前", $mt, $d, $h, $m );
	}
	return $pct;
}

/**
 * 计算参数时间与当前时间差(第二种）
 * @param string $date
 * @param string $isShowDate
 */
function puttime2 ( $date, $isShowDate = true ) {
	$limit = time ( ) - $date;
	if ( $limit < 60 ) {
		return $limit . '秒钟之前';
	}
	if ( $limit >= 60 && $limit < 3600 ) {
		return floor ( $limit / 60 ) . '分钟之前';
	}
	if ( $limit >= 3600 && $limit < 86400 ) {
		return floor ( $limit / 3600 ) . '小时之前';
	}
	if ( $limit >= 86400 and $limit < 259200 ) {
		return floor ( $limit / 86400 ) . '天之前';
	}
	if ( $limit >= 259200 and $isShowDate ) {
		return date ( 'Y-m-d H:i:s', $date );
	} else {
		return '';
	}
} 
